﻿module UItypes

open System.Media
open System.Windows
open System.Windows.Markup
open System.Windows.Media
open System.Windows.Media.Imaging
open System.Windows.Controls
open System.Windows.Input
open Microsoft.FSharp.Core.Operators


type PaintPanel() = 
    inherit Image()
    do base.LayoutTransform <- ScaleTransform()

type ViewPanel() =
    inherit ScrollViewer()
    let mutable lastCenterPositionOnTarget :Point = Point(-1.0,-1.0)
    let mutable lastMousePositionOnTarget :Point = Point(-1.0,-1.0)
    let mutable lastDragPoint :Point = Point(-1.0,-1.0)
    do base.HorizontalScrollBarVisibility <- ScrollBarVisibility.Visible
    do base.VerticalScrollBarVisibility <- ScrollBarVisibility.Visible

    member this.Pan (point :Point) =
        if (not(lastDragPoint = Point(-1.0,-1.0))) then
            let posNow = point
            let dX = posNow.X - lastDragPoint.X
            let dY = posNow.Y - lastDragPoint.Y
            lastDragPoint <- posNow
            this.ScrollToHorizontalOffset(this.HorizontalOffset - dX)
            this.ScrollToVerticalOffset(this.VerticalOffset - dY)


    member this.StartPan (point :Point) =
        let mousePos = point
        if (mousePos.X <= this.ViewportWidth && mousePos.Y < this.ViewportHeight) then //make sure we still can use the scrollbars
            this.Cursor <- Cursors.SizeAll
            lastDragPoint <- mousePos
            this.CaptureMouse() |> ignore

    member this.Zoom (point :Point) (delta :int) (childpos :Point) =
        lastMousePositionOnTarget <- childpos
        if (delta > 0) then
            if((((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX >= 1.0) then
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX + 0.5
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY + 0.5
            else
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX + 0.1
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY + 0.1
        if (delta < 0) then
            if((((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY > 1.0) then
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX - 0.5
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY - 0.5
            else if ((((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY > 0.1) then
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleX - 0.1
                (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY <- (((this.Content :?> PaintPanel).LayoutTransform) :?> ScaleTransform).ScaleY - 0.1
        let centerOfViewport = new Point(this.ViewportWidth / 2.0, this.ViewportHeight / 2.0)
        lastCenterPositionOnTarget <- this.TranslatePoint(centerOfViewport, (this.Content :?> PaintPanel))     

    member this.EndPan() =
        this.Cursor <- Cursors.Arrow
        this.ReleaseMouseCapture()
        lastDragPoint <- Point(-1.0,-1.0)

    member this.OnScrollViewerScrollChanged (sender ) (e :ScrollChangedEventArgs) =
        if (not(e.ExtentHeightChange = 0.0) || not(e.ExtentWidthChange = 0.0)) then
            let mutable targetBefore = Point(-1.0,-1.0)
            let mutable targetNow = Point(-1.0,-1.0)

            if (lastMousePositionOnTarget = Point(-1.0,-1.0)) then
                if (not(lastCenterPositionOnTarget = Point(-1.0,-1.0))) then
                    let centerOfViewport = new Point(this.ViewportWidth/2.0, this.ViewportHeight/2.0)
                    let centerOfTargetNow = this.TranslatePoint(centerOfViewport, (this.Content :?> PaintPanel))
                    targetBefore <- lastCenterPositionOnTarget
                    targetNow <- centerOfTargetNow 
            else
                targetBefore <- lastMousePositionOnTarget;
                targetNow <- Mouse.GetPosition((this.Content :?> PaintPanel));
                lastMousePositionOnTarget <- Point(-1.0,-1.0)

            if (not(targetBefore = Point(-1.0,-1.0))) then
                let dXInTargetPixels = targetNow.X - targetBefore.X
                let dYInTargetPixels = targetNow.Y - targetBefore.Y

                let multiplicatorX = e.ExtentWidth/(this.Content :?> PaintPanel).Width
                let multiplicatorY = e.ExtentHeight/(this.Content :?> PaintPanel).Height

                let newOffsetX = this.HorizontalOffset - dXInTargetPixels*multiplicatorX
                let newOffsetY = this.VerticalOffset - dYInTargetPixels*multiplicatorY

                if (newOffsetX = nan || newOffsetY = nan) then
                    this.ScrollToHorizontalOffset(newOffsetX)
                    this.ScrollToVerticalOffset(newOffsetY)

